// SdkMp3.c

#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <sys/stat.h>
#include <time.h>

#if defined(WIN32)
	#include <direct.h>
	#include <windows.h>
	#define CALLBACK    __stdcall
	#define WINAPI      __stdcall
	#define THREAD_SLEEP(msec) Sleep(msec)
#else // LINUX
	#include <unistd.h>
	#include <pthread.h>
	#include "win_types.h"
	#define WINAPI
	#define CALLBACK
	#define THREAD_SLEEP(msec) usleep(msec * 1000)
#endif

#define ASSERT(x)

#include "cts_sdk.h"

#define AMSG(x)          ((x) ? "有" : "无")

////////////////////////////////////////////////////////////////////////////////////////////////////////////

typedef struct
{
	enSdkDevState eState;
	BYTE AlmInState;  // 报警输入通道状态指示码，每位对应一路报警: 0(无报警), 1(有报警)。
	BYTE AlmOutState; // 报警输出通道状态指示码，每位对应一路报警: 0(无报警), 1(有报警)。
	BOOL bTalkbackEnable;

	FILE * pMp3File1;
	FILE * pMp3File2;
	DWORD dwStartTime;
}TDevState;

static TSdkEventTermRegister g_TermList[MAX_TERM_COUNT];
static TDevState g_TermState[MAX_TERM_COUNT];
static int g_nTermCnt = 0;
static int g_nRecordTermIdx = -1;
static int g_nTalkTermIdx = -1;

static FILE * g_pMp3File1 = NULL;
static FILE * g_pMp3File2 = NULL;
static FILE * g_pPcmFile1 = NULL;
static FILE * g_pPcmFile2 = NULL;
static int g_nPcmTotalLen1 = 0;
static int g_nPcmTotalLen2 = 0;
static const int g_nWaveHeaderSize = 38;
static const int g_nWaveFormatSize = 18;

static BOOL g_bExitSystem = FALSE;//退出系统标志位


static LPCSTR GetStateText(enSdkDevState eState)
{
	switch(eState)
	{
	case TSDK_DEV_STATE_OFFLINE:
		return "不在线";
	case TSDK_DEV_STATE_ONLINE:
		return "在线";
	case TSDK_DEV_STATE_PLAYING:
		return "播放音乐";
	case TSDK_DEV_STATE_TALKING:
		return "通话中";
	case TSDK_DEV_STATE_TALK_PLAY:
		return "通话中并播放音乐";
	}

	return "未知状态";
}

static LPCSTR GetTermType(enSdkDevType eTermType)
{
	switch(eTermType)
	{
	case TSDK_DEV_TYPE_TALK:
		return "[对讲广播终端]";
	case TSDK_DEV_TYPE_BROAD:
		return "[广播终端]";
	case TSDK_DEV_TYPE_MP3:
		return "[网络拾音器]";
	}

	return "[未知类型终端]";
}

static char * GetSaveFolder()
{
#if defined(WIN32)
	return "E:\\temp\\";
#else // LINUX
	return "./";
#endif
}

static void StartRecord(int tidx)
{
	if(g_TermState[tidx].eState == TSDK_DEV_STATE_OFFLINE)
		return;

	if(g_TermState[tidx].pMp3File1 || g_TermState[tidx].pMp3File2)
		return;

	struct tm * ptm_now;
    time_t now;

	now = time(&now);
	g_TermState[tidx].dwStartTime = now;
    ptm_now = localtime(&now); //gmtime(&now);

	char DateDir[128];
	char DevDir[128];
	char FilePath[256];
	char strText[256];
	
	sprintf(DateDir, "%s%d-%02d-%02d", GetSaveFolder(), ptm_now->tm_year+1900/*2000*/, ptm_now->tm_mon+1, ptm_now->tm_mday);
#if defined(WIN32)
	_mkdir(DateDir);
#else // LINUX
	mkdir(DateDir, 0755);
#endif

	sprintf(DevDir, "%s/%s", DateDir, g_TermList[tidx].TermName);
#if defined(WIN32)
	_mkdir(DevDir);
#else // LINUX
	mkdir(DevDir, 0755);
#endif

	sprintf(FilePath, "%s/%02d%02d%02d-1.mp3", DevDir, ptm_now->tm_hour, ptm_now->tm_min, ptm_now->tm_sec);
	g_TermState[tidx].pMp3File1 = fopen(FilePath, "wb");
	if(g_TermState[tidx].pMp3File1)
		sprintf(strText, "==开始录音: %s", FilePath);
	else
		sprintf(strText, "!!!! 错误：创建MP3文件失败 !!!! %s", FilePath);
	printf("%s \n", strText);

	sprintf(FilePath, "%s/%02d%02d%02d-2.mp3", DevDir, ptm_now->tm_hour, ptm_now->tm_min, ptm_now->tm_sec);
	g_TermState[tidx].pMp3File2 = fopen(FilePath, "wb");
	if(g_TermState[tidx].pMp3File2)
		sprintf(strText, "==开始录音: %s", FilePath);
	else
		sprintf(strText, "!!!! 错误：创建MP3文件失败 !!!! %s", FilePath);
	printf("%s \n", strText);

	int nResult = TSDK_Req_OpenTermAudVid(g_TermList[tidx].dwTermID);
	if(nResult != CERR_SUCCESS)
	{
		sprintf(strText, "!!!! 错误：请求网络拾音器MP3流失败！错误代码:%d !!!!", nResult);
		printf("%s \n", strText);
	}

	return;
}

static void StopRecord(int tidx)
{
	if(!g_TermState[tidx].pMp3File1 && !g_TermState[tidx].pMp3File2)
		return;

	char strText[256];
	if(g_TermState[tidx].eState != TSDK_DEV_STATE_OFFLINE)
	{
		int nResult = TSDK_Req_CloseTermAudVid(g_TermList[tidx].dwTermID);
		if(nResult != CERR_SUCCESS)
		{
			sprintf(strText, "!!!! 错误：关闭网络拾音器MP3流失败！错误代码:%d", nResult);
			printf("%s \n", strText);
		}
		THREAD_SLEEP(300);
	}

	if(g_TermState[tidx].pMp3File1)
	{
		fclose(g_TermState[tidx].pMp3File1);
		g_TermState[tidx].pMp3File1 = NULL;
		sprintf(strText, "xx结束录音, 设备:[%s] - 通道1", g_TermList[tidx].TermName);
		printf("%s \n", strText);
	}

	if(g_TermState[tidx].pMp3File2)
	{
		fclose(g_TermState[tidx].pMp3File2);
		g_TermState[tidx].pMp3File2 = NULL;
		sprintf(strText, "xx结束录音, 设备:[%s] - 通道2", g_TermList[tidx].TermName);
		printf("%s \n", strText);
	}
}

static void * Misc_Thread(void * pParam)
{
#if !defined(WIN32)
	pthread_detach(pthread_self());
#endif

	printf("-------> Misc_Thread() : Running \n");
	
	int tidx;
    time_t now;
	DWORD dwCurTime;

	while(!g_bExitSystem)
	{
		for(tidx=0; tidx<g_nTermCnt; tidx++)
		{
			if(g_TermState[tidx].pMp3File1 || g_TermState[tidx].pMp3File2)
			{
				now = time(&now);
				dwCurTime = now;
				if(dwCurTime - g_TermState[tidx].dwStartTime >= 3*60)
					StopRecord(tidx);
			}

			if( (g_TermState[tidx].eState != TSDK_DEV_STATE_OFFLINE) &&
				!g_TermState[tidx].pMp3File1 &&
				!g_TermState[tidx].pMp3File2 )
			{
				StartRecord(tidx);
			}
		}

		THREAD_SLEEP(100);
	}

	for(tidx=0; tidx<g_nTermCnt; tidx++)
	{
		if(g_TermState[tidx].pMp3File1 || g_TermState[tidx].pMp3File2)
			StopRecord(tidx);
	}

	g_bExitSystem = FALSE;

	printf("-------> Misc_Thread() : Exited \n");

	return NULL;
}

int CALLBACK OnTzlSdkCallback(enSdkCbType eCbType, LPVOID pParam, DWORD dwSize, int usr_data)
{
	switch(eCbType)
	{
		case CB_Event_TermRegister:
		{
			ASSERT(dwSize == sizeof(TSdkEventTermRegister));
			TSdkEventTermRegister * pEventTermRegister = (TSdkEventTermRegister*)pParam;
			LPBYTE p = pEventTermRegister->TermMac;
			char strText[256];
			sprintf(strText, "===> %s 请求注册：终端ID:0x%X , MAC地址:%02X-%02X-%02X-%02X-%02X-%02X , IP地址:%s , 名称:%s",
				GetTermType(pEventTermRegister->eTermType), pEventTermRegister->dwTermID, p[0],p[1],p[2],p[3],p[4],p[5], pEventTermRegister->TermIp, pEventTermRegister->TermName);
			printf("%s \n", strText);

/*			// 保存设备注册信息
			for(int i=0; i<g_nTermCnt; i++)
			{
				if(g_TermList[i].dwTermID == pEventTermRegister->dwTermID)
					break;
			}

			if(i < g_nTermCnt)
			{
				// 更新
				g_TermList[i] = *pEventTermRegister;

				g_pMainWnd->StoreTermList();
				g_pMainWnd->UpdateTermListUI();
			}
			else
			{
				// 注册
				if(g_nTermCnt >= MAX_TERM_COUNT)
					return -1; // 返回 0 代表注册成功，否则代表注册失败 !!!

				g_TermList[i] = *pEventTermRegister;
				g_TermState[i].eState = TSDK_DEV_STATE_OFFLINE;
				g_nTermCnt++;

				g_pMainWnd->StoreTermList();
				g_pMainWnd->UpdateTermListUI();
			}
*/			
			return CERR_SUCCESS; // 返回 0 代表注册成功，否则代表注册失败 !!!
		}

		case CB_Event_TermConnect:
		{
			ASSERT(dwSize == sizeof(TSdkEventTermConnect));
			TSdkEventTermConnect * pEventTermConnect = (TSdkEventTermConnect*)pParam;
			LPBYTE p = pEventTermConnect->TermMac;
			char strText[256];
			sprintf(strText, ">>> %s 请求连接：终端ID:0x%X , %s视频 , MAC地址:%02X-%02X-%02X-%02X-%02X-%02X , IP地址:%s , 名称:%s",
				GetTermType(pEventTermConnect->eTermType), pEventTermConnect->dwTermID, (pEventTermConnect->bHasVideo ? "有" : "无"),
				p[0],p[1],p[2],p[3],p[4],p[5], pEventTermConnect->TermIp, pEventTermConnect->TermName);
			printf("%s \n", strText);

			int i;
			for(i=0; i<g_nTermCnt; i++)
			{
				if( (g_TermList[i].dwTermID == pEventTermConnect->dwTermID) &&
					memcmp(g_TermList[i].TermMac, pEventTermConnect->TermMac, 6) == 0)
				{
					break;
				}
			}

			if(i >= g_nTermCnt)
			{
				g_TermList[i].eTermType = pEventTermConnect->eTermType;
				g_TermList[i].dwTermID = pEventTermConnect->dwTermID;
				memcpy(g_TermList[i].TermMac, pEventTermConnect->TermMac, 6);
				strcpy(g_TermList[i].TermIp, pEventTermConnect->TermIp);
				strcpy(g_TermList[i].TermName, pEventTermConnect->TermName);

				g_nTermCnt += 1;
			}

			BOOL bChangeIp = strcmp(g_TermList[i].TermIp, pEventTermConnect->TermIp);
			if(bChangeIp)
				strcpy(g_TermList[i].TermIp, pEventTermConnect->TermIp);

			BOOL bChangeName = strcmp(g_TermList[i].TermName, pEventTermConnect->TermName);
			if(bChangeName)
				strcpy(g_TermList[i].TermName, pEventTermConnect->TermName);

			g_TermList[i].eTermType = pEventTermConnect->eTermType;
			g_TermState[i].bTalkbackEnable = pEventTermConnect->bTalkbackEnable;
			g_TermState[i].eState = TSDK_DEV_STATE_ONLINE;

//			if(bChangeIp || bChangeName)
//				g_pMainWnd->StoreTermList();
//
//			g_pMainWnd->UpdateTermListUI();

//			StartRecord(i);

			return CERR_SUCCESS; // 返回 0 代表允许连接，否则代表不允许 !!!
		}

		case CB_Event_TermCnnLost:
		{
			ASSERT(dwSize == sizeof(TSdkEventTermCnnLost));
			TSdkEventTermCnnLost * pEventTermCnnLost = (TSdkEventTermCnnLost*)pParam;
			char strText[256];
			sprintf(strText, "xxx 终端断开连接：终端ID:0x%X", pEventTermCnnLost->dwTermID);
			printf("%s \n", strText);

			int i;
			for(i=0; i<g_nTermCnt; i++)
			{
				if(g_TermList[i].dwTermID == pEventTermCnnLost->dwTermID)
				{
					g_TermState[i].eState = TSDK_DEV_STATE_OFFLINE;

					StopRecord(i);

					break;
				}
			}

//			g_pMainWnd->UpdateTermListUI();

			break;
		}
		
		case CB_Asw_OpenTermAudVid:
		{
			ASSERT(dwSize == sizeof(TSdkAswOpenTermAudVid));
			TSdkAswOpenTermAudVid * pAswOpenTermAudVid = (TSdkAswOpenTermAudVid*)pParam;
			char strText[256];
			if(pAswOpenTermAudVid->nResult == CERR_SUCCESS)
				sprintf(strText, "打开终端音频成功！终端ID:0x%X ", pAswOpenTermAudVid->dwTermID);
			else
				sprintf(strText, "打开终端音频失败！终端ID:0x%X ，错误代码:%d", pAswOpenTermAudVid->dwTermID, pAswOpenTermAudVid->nResult);
			printf("%s \n", strText);
			break;
		}

		case CB_Asw_CloseTermAudVid:
		{
			ASSERT(dwSize == sizeof(TSdkAswCloseTermAudVid));
			TSdkAswCloseTermAudVid * pAswCloseTermAudVid = (TSdkAswCloseTermAudVid*)pParam;
			char strText[256];
			if(pAswCloseTermAudVid->nResult == CERR_SUCCESS)
				sprintf(strText, "关闭终端音频成功！终端ID:0x%X ", pAswCloseTermAudVid->dwTermID);
			else
				sprintf(strText, "关闭终端音频失败！终端ID:0x%X ，错误代码:%d", pAswCloseTermAudVid->dwTermID, pAswCloseTermAudVid->nResult);
			printf("%s \n", strText);
			break;
		}

		case CB_Asw_GetAudLevel:
		{
			ASSERT(dwSize == sizeof(TSdkAswGetAudLevel));
			TSdkAswGetAudLevel * pAswGetAudLevel = (TSdkAswGetAudLevel*)pParam;
//			g_pMainWnd->m_nCapLevel = pAswGetAudLevel->Level.eCapLevel;
//			g_pMainWnd->m_nAmpLevel = pAswGetAudLevel->Level.eAmpLevel;
//			((CComboBox*)g_pMainWnd->GetDlgItem(IDC_CMB_CAP))->SetCurSel(g_pMainWnd->m_nCapLevel);
//			((CComboBox*)g_pMainWnd->GetDlgItem(IDC_CMB_AMP))->SetCurSel(g_pMainWnd->m_nAmpLevel);
			break;
		}

		case CB_Asw_SetAudLevel:
		{
			ASSERT(dwSize == sizeof(TSdkAswSetAudLevel));
			TSdkAswSetAudLevel * pAswSetAudLevel = (TSdkAswSetAudLevel*)pParam;
			char strText[256];
			if(pAswSetAudLevel->nResult == CERR_SUCCESS)
				sprintf(strText, "设置终端音量成功！终端ID:0x%X ", pAswSetAudLevel->dwTermID);
			else
				sprintf(strText, "设置终端音量失败！终端ID:0x%X ，错误代码:%d", pAswSetAudLevel->dwTermID, pAswSetAudLevel->nResult);
			printf("%s \n", strText);
			break;
		}

		case CB_Asw_SetDbAlmCfg:
		{
			ASSERT(dwSize == sizeof(TSdkAswSetDbAlmCfg));
			TSdkAswSetDbAlmCfg * pAswSetDbAlmCfg = (TSdkAswSetDbAlmCfg*)pParam;
			char strText[256];
			if(pAswSetDbAlmCfg->nResult == CERR_SUCCESS)
				sprintf(strText, "修改终端配置成功！终端ID:0x%X ", pAswSetDbAlmCfg->dwTermID);
			else
				sprintf(strText, "修改终端配置失败！终端ID:0x%X ，错误代码:%d", pAswSetDbAlmCfg->dwTermID, pAswSetDbAlmCfg->nResult);
			printf("%s \n", strText);
			break;
		}

		case CB_Asw_OpenTermTalk:
		{
			ASSERT(dwSize == sizeof(TSdkAswOpenTermTalk));
			TSdkAswOpenTermTalk * pAswOpenTermTalk = (TSdkAswOpenTermTalk*)pParam;
			char strText[256];
			if(pAswOpenTermTalk->nResult == CERR_SUCCESS)
				sprintf(strText, "打开终端对讲成功！终端ID:0x%X ", pAswOpenTermTalk->dwTermID);
			else
				sprintf(strText, "打开终端对讲失败！终端ID:0x%X ，错误代码:%d", pAswOpenTermTalk->dwTermID, pAswOpenTermTalk->nResult);
			printf("%s \n", strText);
			break;
		}

		case CB_Asw_CloseTermTalk:
		{
			ASSERT(dwSize == sizeof(TSdkAswCloseTermTalk));
			TSdkAswCloseTermTalk * pAswCloseTermTalk = (TSdkAswCloseTermTalk*)pParam;
			char strText[256];
			if(pAswCloseTermTalk->nResult == CERR_SUCCESS)
				sprintf(strText, "关闭终端对讲成功！终端ID:0x%X ", pAswCloseTermTalk->dwTermID);
			else
				sprintf(strText, "关闭终端对讲失败！终端ID:0x%X ，错误代码:%d", pAswCloseTermTalk->dwTermID, pAswCloseTermTalk->nResult);
			printf("%s \n", strText);
			break;
		}

		case CB_Post_TermState:
		{
			ASSERT(dwSize == sizeof(TSdkPostTermState));
			TSdkPostTermState * pPostTermState = (TSdkPostTermState*)pParam;
			
			int i;
			for(i=0; i<g_nTermCnt; i++)
			{
				if(g_TermList[i].dwTermID == pPostTermState->dwTermID)
				{
					g_TermState[i].eState = pPostTermState->eTermState;
					g_TermState[i].AlmInState = pPostTermState->AlmInState;
					g_TermState[i].AlmOutState = pPostTermState->AlmOutState;
					break;
				}
			}

			char strText[256];
			sprintf(strText, "终端ID:0x%X 终端状态:%s , IO报警 == 输入1:%s , 输入2:%s , 输出1:%s , 输出2:%s", pPostTermState->dwTermID, GetStateText(pPostTermState->eTermState),
				AMSG(pPostTermState->AlmInState & 0x1), AMSG((pPostTermState->AlmInState >> 1) & 0x1),
				AMSG(pPostTermState->AlmOutState & 0x1), AMSG((pPostTermState->AlmOutState >> 1) & 0x1));
			printf("%s \n", strText);
			break;
		}

		case CB_Post_AlmNotify:
		{
			ASSERT(dwSize == sizeof(TSdkPostAlmNotify));
			TSdkPostAlmNotify * pPostAlmNotify = (TSdkPostAlmNotify*)pParam;
			char strText[256];
			if((pPostAlmNotify->eAlmType & SDK_ALMTYPE_DB_ALARM) == SDK_ALMTYPE_DB_ALARM)
				sprintf(strText, "终端喧哗报警 !!!    终端ID:0x%X   通道号:%d", pPostAlmNotify->dwTermID, pPostAlmNotify->nChanNum);
			else
				sprintf(strText, "终端其他报警 !!!    终端ID:0x%X", pPostAlmNotify->dwTermID);
			printf("%s \n", strText);
			break;
		}

		case CB_Data_TermMp3L:
		{
			ASSERT(dwSize == sizeof(TSdkDataTermMp3L));
			TSdkDataTermMp3L * pDataTermMp3L = (TSdkDataTermMp3L*)pParam;
//			TRACE("== MP3音频 ID:%X ：大小 %d 字节\n", pDataTermMp3L->dwTermID,pDataTermMp3L->nDataSize);
//			if(g_pMp3File1 && pDataTermMp3L->dwTermID == g_TermList[g_nRecordTermIdx].dwTermID)
//				fwrite(pDataTermMp3L->pMp3Data, 1, pDataTermMp3L->nDataSize, g_pMp3File1);

			int i;
			for(i=0; i<g_nTermCnt; i++)
			{
				if(g_TermList[i].dwTermID == pDataTermMp3L->dwTermID)
				{
					if(g_TermState[i].pMp3File1)
						fwrite(pDataTermMp3L->pMp3Data, 1, pDataTermMp3L->nDataSize, g_TermState[i].pMp3File1);
					break;
				}
			}

			break;
		}

		case CB_Data_TermMp3R:
		{
			ASSERT(dwSize == sizeof(TSdkDataTermMp3R));
			TSdkDataTermMp3R * pDataTermMp3R = (TSdkDataTermMp3R*)pParam;
//			TRACE("== MP3音频 ID:%X ：大小 %d 字节\n", pDataTermMp3R->dwTermID,pDataTermMp3R->nDataSize);
//			if(g_pMp3File2 && pDataTermMp3R->dwTermID == g_TermList[g_nRecordTermIdx].dwTermID)
//				fwrite(pDataTermMp3R->pMp3Data, 1, pDataTermMp3R->nDataSize, g_pMp3File2);

			int i;
			for(i=0; i<g_nTermCnt; i++)
			{
				if(g_TermList[i].dwTermID == pDataTermMp3R->dwTermID)
				{
					if(g_TermState[i].pMp3File2)
						fwrite(pDataTermMp3R->pMp3Data, 1, pDataTermMp3R->nDataSize, g_TermState[i].pMp3File2);
					break;
				}
			}

			break;
		}

		case CB_Data_TermPcmL:
		{
			ASSERT(dwSize == sizeof(TSdkDataTermPcmL));
			TSdkDataTermPcmL * pDataTermPcmL = (TSdkDataTermPcmL*)pParam;
//			TRACE("== Pcm音频 ID:%X ：大小 %d 字节\n", pDataTermPcmL->dwTermID,pDataTermPcmL->nDataSize);
			if(g_pPcmFile1 && pDataTermPcmL->dwTermID == g_TermList[g_nRecordTermIdx].dwTermID)
				fwrite(pDataTermPcmL->pPcmData, 1, pDataTermPcmL->nDataSize, g_pPcmFile1);
			g_nPcmTotalLen1 += pDataTermPcmL->nDataSize;
			break;
		}

		case CB_Data_TermPcmR:
		{
			ASSERT(dwSize == sizeof(TSdkDataTermPcmR));
			TSdkDataTermPcmR * pDataTermPcmR = (TSdkDataTermPcmR*)pParam;
//			TRACE("== Pcm音频 ID:%X ：大小 %d 字节\n", pDataTermPcmR->dwTermID,pDataTermPcmR->nDataSize);
			if(g_pPcmFile2 && pDataTermPcmR->dwTermID == g_TermList[g_nRecordTermIdx].dwTermID)
				fwrite(pDataTermPcmR->pPcmData, 1, pDataTermPcmR->nDataSize, g_pPcmFile2);
			g_nPcmTotalLen2 += pDataTermPcmR->nDataSize;
			break;
		}

		case CB_Data_TermAudio:
		{
			ASSERT(dwSize == sizeof(TSdkDataTermAudio));
			TSdkDataTermAudio * pDataTermAudio = (TSdkDataTermAudio*)pParam;
//			TRACE("== 终端音频 ID:%X ：大小 %d 字节\n", pDataTermAudio->dwTermID,pDataTermAudio->nDataSize);
			TSDK_Player_AudVidAdd(1, TSDK_AUDIO, pDataTermAudio->pAudData, pDataTermAudio->nDataSize);
			break;
		}

		case CB_Data_PcMicAudio:
		{
			ASSERT(dwSize == sizeof(TSdkDataPcMicAudio));
			TSdkDataPcMicAudio * pDataPcAudio = (TSdkDataPcMicAudio*)pParam;
//			TRACE("== 电脑麦克风音频：大小 %d 字节\n", pDataPcAudio->nDataSize);

			if(g_nTalkTermIdx != -1)
			{
				TSDK_Send_TalkAudio(g_TermList[g_nTalkTermIdx].dwTermID,
					pDataPcAudio->pPcmData, pDataPcAudio->nDataSize);
			}

			break;
		}
		
		case CB_Post_TermDbValL:
		{
			ASSERT(dwSize == sizeof(TSdkPostTermDbValL));
			TSdkPostTermDbValL * pPostTermDbValL = (TSdkPostTermDbValL*)pParam;
			char strText[256];
			sprintf(strText, "%d", pPostTermDbValL->nDbVal);
			printf("%s \n", strText);
			break;
		}

		case CB_Post_TermDbValR:
		{
			ASSERT(dwSize == sizeof(TSdkPostTermDbValR));
			TSdkPostTermDbValR * pPostTermDbValR = (TSdkPostTermDbValR*)pParam;
			char strText[256];
			sprintf(strText, "%d", pPostTermDbValR->nDbVal);
			printf("%s \n", strText);
			break;
		}

		default:
		{
			ASSERT(FALSE);
			break;
		}
	}

	return CERR_SUCCESS;
}

int main(int argc, char* argv[])
{
	memset(g_TermList, 0, sizeof(g_TermList));
	memset(g_TermState, 0, sizeof(g_TermState));
	g_nTermCnt = 0;

	int nResult = TSDK_Init(OnTzlSdkCallback, TRUE, 0x12345678);
	char strText[256];
	if(nResult == CERR_SUCCESS)
		sprintf(strText, "SDK 初始化成功！");
	else
		sprintf(strText, "SDK 初始化失败！错误代码:%d", nResult);
	printf("%s \n", strText);

#if defined(WIN32)
    DWORD threadid;
    ::CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)Misc_Thread, NULL, 0, &threadid);
#else // LINUX
	pthread_t threadid;
	pthread_create(&threadid, NULL, Misc_Thread, NULL);
#endif

	printf(":: press 'd' to show device list ..\n:: press 'q' to exit !!\n ");

    while(1) 
	{
		char ch = getchar();

		if(ch == 'q')
		{
			break;
		}
		else if(ch == '\n')
		{
			printf(":: press 'd' to show device list ..\n:: press 'q' to exit !!\n ");
			continue;
		}
		else if(ch == 'd')
		{
			int i;
			for(i=0; i<g_nTermCnt; i++)
			{
				sprintf(strText, "== DevIdx:%d , Type:%s , DevID:0x%x, DevIP:%s , DevName:%s , State:%s",
					i,
					GetTermType(g_TermList[i].eTermType),
					g_TermList[i].dwTermID,
					g_TermList[i].TermIp,
					g_TermList[i].TermName,
					GetStateText(g_TermState[i].eState));
				printf("%s \n", strText);
			}
		}

		printf("\n");
	}
		
    printf("exiting this sample ...\n");

	g_bExitSystem = TRUE;
	while(g_bExitSystem)
	{
		THREAD_SLEEP(100);
	}

	TSDK_DeInit();

	printf("exit successfully ! \n");

	exit(0);
	return 0;
}
